﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using GN.Pay.Client.Notify;
using System.Collections.Specialized;
using GN.Pay.Client.Utils;

namespace GN.Pay.Client.Services
{
    /// <summary>
    /// 通知服务
    /// </summary>
    class NotifyService : APayService, INotifyService
    {
        /// <summary>
        /// 实例化 NotifyService 类新实例
        /// </summary>
        /// <param name="client">客户端</param>
        public NotifyService(IServiceClient client)
            : base(client)
        {

        }

        private NameValueCollection GetQueryString(HttpRequestBase request)
        {
            if ("POST".Equals(request.HttpMethod, StringComparison.InvariantCultureIgnoreCase))
            {
                return request.Form;
            }
            return request.QueryString;
        }

        /// <summary>
        /// 获取查询字典
        /// </summary>
        /// <param name="request">请求</param>
        /// <returns></returns>
        private IDictionary<string, string> GetQueryDictionary(HttpRequestBase request)
        {
            ExceptionUtils.CheckNotNull(request, nameof(request));
            NameValueCollection requestPara = GetQueryString(request);
            Dictionary<string, string> inputDic = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
            foreach (string str in requestPara.AllKeys)
            {
                if (str != null)
                {
                    inputDic.Add(str, requestPara[str]);
                }
            }
            return inputDic;
        }

        /// <summary>
        /// 创建付款通知
        /// </summary>
        /// <param name="request">请求</param>
        /// <returns></returns>
        public PayNotifyMessage CreatePayNotify(HttpRequestBase request)
        {
            return CreatePayNotify(GetQueryDictionary(request));
        }

        /// <summary>
        /// 创建付款通知
        /// </summary>
        /// <param name="requestDictionary">请求字典</param>
        /// <returns></returns>
        public PayNotifyMessage CreatePayNotify(IDictionary<string, string> requestDictionary)
        {
            return new PayNotifyMessage(requestDictionary, this.Client.PayConfigure);
        }

        /// <summary>
        /// 创建退款通知
        /// </summary>
        /// <param name="request">请求</param>
        /// <returns></returns>
        public RefundNotifyMessage CreateRefundNotify(HttpRequestBase request)
        {
            return CreateRefundNotify(GetQueryDictionary(request));
        }

        /// <summary>
        /// 创建退款通知
        /// </summary>
        /// <param name="requestDictionary">请求字典</param>
        /// <returns></returns>
        public RefundNotifyMessage CreateRefundNotify(IDictionary<string, string> requestDictionary)
        {
            return new RefundNotifyMessage(requestDictionary, this.Client.PayConfigure);
        }        

        /// <summary>
        /// 通知处理
        /// </summary>
        /// <param name="request">请求</param>
        /// <param name="response">响应</param>
        /// <param name="notifyFactory">通知工厂</param>
        /// <param name="notifyCall">通知回调</param>
        private void NotifyHandle<TMsg>(HttpRequestBase request,
            HttpResponseBase response,
            Func<HttpRequestBase, TMsg> notifyFactory,
            Action<TMsg> notifyCall) where TMsg : NotifyMessage
        {
            ExceptionUtils.CheckNotNull(request, nameof(request));
            ExceptionUtils.CheckNotNull(response, nameof(response));
            ExceptionUtils.CheckNotNull(notifyFactory, nameof(notifyFactory));
            ExceptionUtils.CheckNotNull(notifyCall, nameof(notifyCall));
            TMsg msg = null;
            try
            {
                msg = notifyFactory(request);
                if (msg.SginVerify())
                {
                    notifyCall(msg);
                    response.Write(msg.SuccessMessage());
                }
                else
                {
                    response.Write(msg.FailMessage("验签不通过"));
                }
            }
            catch (Exception err)
            {
                if (msg != null)
                {
                    response.Write(msg.FailMessage(err.Message));
                }
                else
                {
                    response.Write(err.Message);
                }
            }
        }

        /// <summary>
        /// 付款通知
        /// </summary>
        /// <param name="request">请求</param>
        /// <param name="response">响应</param>
        /// <param name="notifyCallback">通知回调</param>
        public void PayNotifyHandle(HttpRequestBase request,
            HttpResponseBase response,
            Action<PayNotifyMessage> notifyCallback)
        {
            NotifyHandle(request, response, (r) =>
            {
                return CreatePayNotify(request);
            }, notifyCallback);
        }

        /// <summary>
        /// 异步付款通知
        /// </summary>
        /// <param name="request">请求</param>
        /// <param name="response">响应</param>
        /// <param name="notifyCallback">通知回调</param>
        public async Task PayNotifyHandleAsync(HttpRequestBase request,
            HttpResponseBase response,
            Action<PayNotifyMessage> notifyCallback)
        {
            await Task.Run(() => {
                PayNotifyHandle(request, response, notifyCallback);
            });
        }

        /// <summary>
        /// 退款通知
        /// </summary>
        /// <param name="request">请求</param>
        /// <param name="response">响应</param>
        /// <param name="notifyCallback">通知回调</param>
        public void RefundNotifyHandle(HttpRequestBase request,
            HttpResponseBase response,
            Action<RefundNotifyMessage> notifyCallback)
        {
            NotifyHandle(request, response, (r) =>
            {
                return CreateRefundNotify(request);
            }, notifyCallback);
        }

        /// <summary>
        /// 异步退款通知
        /// </summary>
        /// <param name="request">请求</param>
        /// <param name="response">响应</param>
        /// <param name="notifyCallback">通知回调</param>
        public async Task RefundNotifyHandleAsync(HttpRequestBase request,
             HttpResponseBase response,
             Action<RefundNotifyMessage> notifyCallback)
        {
            await Task.Run(() => {
                RefundNotifyHandle(request, response, notifyCallback);
            });
        }

        /// <summary>
        /// 创建转账通知
        /// </summary>
        /// <param name="request">请求</param>
        /// <returns></returns>
        public TransfersNotifyMessage CreateTransfersNotify(HttpRequestBase request)
        {
            return CreateTransfersNotify(GetQueryDictionary(request));
        }

        /// <summary>
        /// 创建转账通知
        /// </summary>
        /// <param name="requestDictionary">请求字典</param>
        /// <returns></returns>
        public TransfersNotifyMessage CreateTransfersNotify(IDictionary<string, string> requestDictionary)
        {
            return new TransfersNotifyMessage(requestDictionary, this.Client.PayConfigure);
        }

        /// <summary>
        /// 转账通知处理
        /// </summary>
        /// <param name="request">请求</param>
        /// <param name="response">响应</param>
        /// <param name="notifyCallback">通知回调</param>
        public void TransfersNotifyHandle(HttpRequestBase request, HttpResponseBase response, Action<TransfersNotifyMessage> notifyCallback)
        {
            NotifyHandle(request, response, (r) =>
            {
                return CreateTransfersNotify(request);
            }, notifyCallback);
        }

        /// <summary>
        /// 转账通知处理
        /// </summary>
        /// <param name="request">请求</param>
        /// <param name="response">响应</param>
        /// <param name="notifyCallback">通知回调</param>
        public async Task TransfersNotifyHandleAsync(HttpRequestBase request, HttpResponseBase response, Action<TransfersNotifyMessage> notifyCallback)
        {
            await Task.Run(() => {
                TransfersNotifyHandle(request, response, notifyCallback);
            });
        }
    }
}
